package timeline.util.master;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

import timeline.util.TimeLine;
import timeline.util.TimeLineServer;
import timeline.util.TimeLine.RunFinishResult;
import timeline.util.TimeLineClassLoader;
import timeline.util.TimeLineClient;
import timeline.util.TimeLineClient.ClientCallBack;
import timeline.util.model.TaskModel;
import timeline.util.model.TaskSubmitModel;
import timeline.util.model.TimeLineConnectModel;

public class TImeLineMaster {
	private final static Logger logger = Logger.getLogger(TimeLineServer.class
			.getName());
	private ServerSocket server;
	private String serverName;
	private List<TimeLineConnectModel> connectModels;
	TimeLineClient timeLineClient ;
	
	public static void main(String[] args) {
		TImeLineMaster master = new TImeLineMaster();
		for(String str :args){
			System.out.print(" "+str);
		}
		System.out.println("--");
		try {
			master.init(args[0], Integer.parseInt(args[1]));
		} catch (NumberFormatException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void init(String serverName,final int port) throws IOException {
		System.out.println(""+this+" init in "+serverName+":"+port);
		this.serverName = serverName;
		connectModels = new ArrayList<TimeLineConnectModel>();
		new Thread(new Runnable() {
			public void run() {
				try {
					server = new ServerSocket(port);
					while (true) {
						Socket socket = server.accept();
						invoke(socket);
					}
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}).start();
	}

	public void terminal() throws IOException {
		server.close();
	}

	private  void invoke(final Socket socket) throws IOException {
		new Thread(new Runnable() {
			public void run() {
				try {
					final ObjectInputStream is = new ObjectInputStream(
							new BufferedInputStream(socket.getInputStream()));
					final ObjectOutputStream os = new ObjectOutputStream(
							socket.getOutputStream());
					Object obj = is.readObject();
					//---------------------------------------
					if(obj instanceof TimeLineConnectModel){
						TimeLineConnectModel connectModel = (TimeLineConnectModel) obj;
						connectModels.add(connectModel);
						System.out.println(""+connectModel.toString());
						os.writeObject("connect success from master");
						os.flush();
					}else if (obj instanceof TaskSubmitModel) {
						TaskSubmitModel taskSubmitModel = (TaskSubmitModel) obj;
						System.out.println(""+taskSubmitModel.toString());
						TimeLineClassLoader classLoader = new TimeLineClassLoader(taskSubmitModel.filePath);
						TaskModel taskModel = new TaskModel();
						taskModel.data = classLoader.loadClassData(taskSubmitModel.runningTarget);
						taskModel.ObjName = taskSubmitModel.runningTarget;
						
						timeLineClient = new TimeLineClient();
						boolean issend = false;
						if(taskSubmitModel.serverName.equals("auto")) {
							issend = true;
							
							timeLineClient.send(connectModels.get(0).WorkerIpAddress, Integer.parseInt(connectModels.get(0).port),
									taskModel, new ClientCallBack() {
										
										@Override
										public void OnCallBack(ConcurrentHashMap<String, Object> object) {
											// TODO Auto-generated method stub
											try {
												os.writeObject(object);
												os.flush();
												
											} catch (IOException e) {
												// TODO Auto-generated catch block
												e.printStackTrace();
												
											}
										}
									});
						}
						for(TimeLineConnectModel timeLineConnectModel:connectModels) {
							if(timeLineConnectModel.name.equals(taskSubmitModel.serverName)) {
								issend = true;
								timeLineClient.send(timeLineConnectModel.WorkerIpAddress, Integer.parseInt(timeLineConnectModel.port),
										taskModel, new ClientCallBack() {
											
											@Override
											public void OnCallBack(ConcurrentHashMap<String, Object> object) {
												// TODO Auto-generated method stub
												try {
													os.writeObject(object);
													os.flush();
												} catch (IOException e) {
													// TODO Auto-generated catch block
													e.printStackTrace();
												}
											}
										});
							}
						}
						if(!issend) {
							os.writeObject("no worker to exec!");
							os.flush();
						}
					}
					else{
						System.out.print("unknow command!");
					}
					
				} catch (IOException ex1) {
					logger.log(Level.SEVERE, null, ex1);
				} catch (Exception ex2) {
					logger.log(Level.SEVERE, null, ex2);
					try {
						final ObjectOutputStream os = new ObjectOutputStream(
								socket.getOutputStream());
						os.writeObject(ex2.getMessage());
						os.flush();
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
		}).start();
	}
}
